package com.google.coffeeshop.business;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDTrueTypeFont;

import vn.bang.utility.DateUtil;
import vn.bang.utility.FileUtil;
import vn.bang.utility.JpaUtil;

import com.google.coffeeshop.GeneralConstants;
import com.google.coffeeshop.dao.DAOFactory;
import com.google.coffeeshop.dao.InvoiceDAO;
import com.google.coffeeshop.dao.OrderDAO;
import com.google.coffeeshop.dao.SeatDAO;
import com.google.coffeeshop.entity.InvoiceDTO;
import com.google.coffeeshop.entity.InvoiceLineDTO;
import com.google.coffeeshop.entity.OrderDTO;
import com.google.coffeeshop.entity.OrderLineDTO;
import com.google.coffeeshop.entity.SeatDTO;
import com.google.coffeeshop.log.Log;

public class PaymentBusiness extends AbstractBaseBusiness {

	static public OrderDTO findOrderUnProcessedBySeatId(long seatId) {
		OrderDTO order = null;
		final EntityManager entityManager = createEntityManager();
		try {
			JpaUtil.beginTransaction(entityManager);
			order = DAOFactory.createOrderDAO(entityManager).findBySeatId(seatId, GeneralConstants.ORDER_UNPROCESSED_STATUS);
			JpaUtil.commitEntityManager(entityManager);

		} catch (PersistenceException persistenceException) {
			JpaUtil.rollbackEntityManager(entityManager);
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return order;
	}
	
	static public OrderDTO storeNewOrder(final List<OrderLineDTO> orderLines,
			final long seatId) {
		OrderDTO order = null;
		final EntityManager entityManager = createEntityManager();
		try {
			JpaUtil.beginTransaction(entityManager);
			order = createNewOrder(orderLines, seatId, entityManager);
			saveNewOrder(order, entityManager);

			changeSeatStatus(seatId, GeneralConstants.SEAT_BUSY_STATUS,
					entityManager);
			JpaUtil.commitEntityManager(entityManager);

		} catch (PersistenceException persistenceException) {
			JpaUtil.rollbackEntityManager(entityManager);
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return order;
	}

	static public InvoiceDTO exportInvoice(final OrderDTO order) {
		InvoiceDTO invoice = null;
		final EntityManager entityManager = createEntityManager();
		try {
			JpaUtil.beginTransaction(entityManager);
			invoice = createInvoice(order);
			saveNewInvoice(invoice, entityManager);
			exportInvoiceToPrinter(invoice);
			JpaUtil.commitEntityManager(entityManager);

		} catch (PersistenceException persistenceException) {
			JpaUtil.rollbackEntityManager(entityManager);
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}

		return invoice;
	}
	
	static public void completePayment(long invoiceId, long orderId, long seatId) {
		final EntityManager entityManager = createEntityManager();
		try {
			JpaUtil.beginTransaction(entityManager);
				InvoiceDTO invoice = DAOFactory.createInvoiceDAO(entityManager).find(invoiceId);
				invoice.setStatus(GeneralConstants.INVOICE_PAID_STATUS);
				DAOFactory.createInvoiceDAO(entityManager).save(invoice);
				
				OrderDTO order = DAOFactory.createOrderDAO(entityManager).find(orderId);
				order.setStatus(GeneralConstants.ORDER_PROCESSED_STATUS);
				DAOFactory.createOrderDAO(entityManager).save(order);
				
				
				SeatDTO seat = DAOFactory.createSeatDAO(entityManager).find(seatId);
				seat.setStatus(GeneralConstants.SEAT_USABLE_STATUS);
				DAOFactory.createSeatDAO(entityManager).save(seat);
			JpaUtil.commitEntityManager(entityManager);

		} catch (PersistenceException persistenceException) {
			JpaUtil.rollbackEntityManager(entityManager);
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
	}

	static public void changeStatusAfterPaid(long seatId, long orderId,
			long invoiceId) {
		EntityManager entityManager = createEntityManager();
		try {
			JpaUtil.beginTransaction(entityManager);
			changeSeatStatus(seatId, GeneralConstants.SEAT_USABLE_STATUS,
					entityManager);
			changeOrderStatus(orderId, GeneralConstants.ORDER_PROCESSED_STATUS,
					entityManager);
			changeInvoiceStatus(invoiceId,
					GeneralConstants.INVOICE_PAID_STATUS, entityManager);
			JpaUtil.commitEntityManager(entityManager);

		} catch (PersistenceException persistenceException) {
			JpaUtil.rollbackEntityManager(entityManager);
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
	}

	private static void exportInvoiceToPrinter(final InvoiceDTO invoice) {
		PDDocument doc = null;
		PDPage page = null;

		try {
			doc = new PDDocument();
			page = new PDPage();

			doc.addPage(page);

			PDPageContentStream content = new PDPageContentStream(doc, page);
			
			writeInvoicePDFContent(doc, content, invoice);
			
			content.close();
			doc.save(FileUtil.getRelativePathFromProjectPath("invoice_pdf\\invoice-" + DateUtil.getNowString() + ".pdf"));
			doc.close();
		} catch (Exception e) {
			System.out.println(e);
		}
	}

	private static void writeInvoicePDFContent(PDDocument doc, PDPageContentStream content, InvoiceDTO invoice) throws IOException {
		
		PDFont font = PDTrueTypeFont.loadTTF( doc, new File( "fonts/VNTIMEB.TTF" ) );  // Windows Russian font imported to write the Russian text.
//		PDFont font = PDType1Font.TIMES_ROMAN;
//		COSDictionary cosDic = new COSDictionary(); 
//		cosDic.setString( COSName.getPDFName("Ercyrillic"), "0420 " ); // Russian letter.
//		font.setFontEncoding( new DictionaryEncoding( cosDic ) );
//		font.setToUnicode(doc);
//		BaseFont unicode = BaseFont.createFont(fontFile.getAbsolutePath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

		content.setFont(font, 32);
		drawString(content, 250, 730, "Invoice");
		content.setFont(font, 14);
		int xBegin = 50;
		int yBegin = 600;
		int lineDistance = 30;
		int number = 1;
		drawHeaderInvoiceLine(content, xBegin, yBegin);
		for (InvoiceLineDTO invoiceLine : invoice.getInvoiceLines()) {
			yBegin -= lineDistance;
			drawInvoiceLine(content, xBegin, yBegin, number, invoiceLine);
			number++;
		}
		drawTotalAmount(content, invoice, xBegin, yBegin, lineDistance);
	}

	public static void drawTotalAmount(PDPageContentStream content,
			InvoiceDTO invoice, int xBegin, int yBegin, int lineDistance)
			throws IOException {
		xBegin += 320;
		yBegin -= lineDistance + 10;
		drawString(content, xBegin, yBegin, "Total:");
		drawString(content, xBegin + 100, yBegin, String.valueOf(invoice.getAmount()));
	}

	public static void drawHeaderInvoiceLine(PDPageContentStream content,
			int xBegin, int yBegin) throws IOException {
		drawString(content, xBegin, yBegin, "ID");
		drawString(content, xBegin + 20, yBegin, "Product");
		drawString(content, xBegin + 20 + 200, yBegin, "Price");
		drawString(content, xBegin + 20 + 200 + 100, yBegin, "Quantity");
		drawString(content, xBegin + 20 + 200 + 100 + 100, yBegin, "Amount");
	}

	private static void drawInvoiceLine(PDPageContentStream content, int xBegin,
			int yBegin, int number, InvoiceLineDTO invoiceLine)
			throws IOException {
		drawString(content, xBegin, yBegin, String.valueOf(number));
		drawString(content, xBegin + 20, yBegin, invoiceLine.getOrderLine().getProduct().getName());
		drawString(content, xBegin + 20 + 200, yBegin, String.valueOf(invoiceLine.getOrderLine().getPriceOfUnit()));
		drawString(content, xBegin + 20 + 200 + 100, yBegin, String.valueOf(invoiceLine.getOrderLine().getQuantity()));
		drawString(content, xBegin + 20 + 200 + 100 + 100, yBegin, String.valueOf(
				invoiceLine.getOrderLine().getPriceOfUnit() * invoiceLine.getOrderLine().getQuantity()));
	}


	
	public static void drawString(PDPageContentStream content, int xBegin,
			int yBegin, String str) throws IOException {
		content.beginText();
		content.moveTextPositionByAmount(xBegin, yBegin);
		content.drawString(str);
		content.endText();
	}
	
	
	
	private static InvoiceDTO createInvoice(final OrderDTO order) {
		final InvoiceDTO invoice = new InvoiceDTO();
		invoice.setOrder(order);
		invoice.setAmount(order.getAmount());
		invoice.setStatus(GeneralConstants.INVOICE_UNPAID_STATUS);
		invoice.setCode(order.getCode() + String.valueOf(order.getId()));
		invoice.setCreateDate(DateUtil.getNow());
		invoice.setEmployee(order.getEmployee());
		invoice.setInvoiceLines(createInvoiceLines(order, invoice));
		return invoice;
	}

	private static List<InvoiceLineDTO> createInvoiceLines(OrderDTO order,
			InvoiceDTO invoice) {
		List<InvoiceLineDTO> invoiceLines = new ArrayList<InvoiceLineDTO>();
		for (OrderLineDTO orderLine : order.getOrderLines()) {
			InvoiceLineDTO invoiceLine = new InvoiceLineDTO();
			invoiceLine.setOrderLine(orderLine);
			invoiceLine.setInvoice(invoice);
			invoiceLines.add(invoiceLine);
		}
		return invoiceLines;
	}

	private static void saveNewInvoice(final InvoiceDTO invoice,
			final EntityManager entityManager) {
		final InvoiceDAO invoiceDAO = DAOFactory
				.createInvoiceDAO(entityManager);
		invoiceDAO.persist(invoice);
	}

	private static void saveNewOrder(final OrderDTO order,
			final EntityManager entityManager) {
		final OrderDAO orderDAO = DAOFactory.createOrderDAO(entityManager);
		orderDAO.persist(order);
	}

	private static OrderDTO createNewOrder(final List<OrderLineDTO> orderLines,
			final long seatId, final EntityManager entityManager) {
		final SeatDAO seatDAO = DAOFactory.createSeatDAO(entityManager);
		final SeatDTO seat = seatDAO.find(seatId);

		final OrderDTO order = new OrderDTO();
		order.setSeat(seat);
		order.setStatus(GeneralConstants.ORDER_UNPROCESSED_STATUS);
		for (OrderLineDTO orderLineDTO : orderLines) {
			orderLineDTO.setOrder(order);
		}
		return order;
	}

}
